package com.codinghero.zqlb.spider;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map.Entry;

import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.HasParentFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.nodes.TextNode;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

import com.codinghero.util.DateUtils;
import com.codinghero.util.ListUtils;
import com.codinghero.util.StringUtils;
import com.codinghero.zqlb.match.RawMatch;
import com.codinghero.zqlb.match.SoccerMatch;
import com.codinghero.zqlb.spider.handler.ChannelFilterHandler;
import com.sina.sae.fetchurl.SaeFetchurl;

public class FYZBSpider {

	public List<RawMatch> parse(String url, String encoding) {
		try {
			SaeFetchurl fetchUrl = new SaeFetchurl();
			String content = fetchUrl.fetch(url);
			//content = new String(content.getBytes("ISO-8859-1"), encoding);
			Parser parser = Parser.createParser(content, encoding);
			
			NodeFilter tableTagFilter = new TagNameFilter("table");
			NodeFilter airtableFilter = new HasAttributeFilter("id", "air-table");
			NodeFilter tableFilter = new AndFilter(tableTagFilter, airtableFilter);
			
			NodeFilter thFilter = new TagNameFilter("th");
			NodeFilter trFilter = new TagNameFilter("tr");
			NodeFilter dateAndMatchFilter = new OrFilter(thFilter, trFilter);
			
			NodeFilter allFilter = new AndFilter(new HasParentFilter(tableFilter), dateAndMatchFilter);
			
			NodeList nodeList = parser.parse(allFilter);
			
			List<RawMatch> matchList = this.parse(nodeList);
			this.filter(matchList);
			return matchList;
		} catch (ParserException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	private List<RawMatch> parse(NodeList nodeList) {
		List<RawMatch> matches = new ArrayList<RawMatch>();
		int year = Integer.parseInt(DateUtils.getCurYear());
		int month = -1, day = -1;
		
		for (int i = 0; i < nodeList.size(); i++) {
			if (nodeList.elementAt(i).getChildren() == null)
				continue;
			String rawStr = nodeList.elementAt(i).getChildren().asString();
			if (rawStr.matches("^.*[0-9]{1,2}月[0-9]{1,2}日.*$")) {
				int monthIndex = rawStr.indexOf("月");
				String monthStr = rawStr.substring(0, monthIndex);
				String dayStr = rawStr.substring(monthIndex + 1,
						rawStr.indexOf("日"));
				if(Integer.parseInt(monthStr)<month)
					year++;
				month = Integer.parseInt(monthStr);
				day = Integer.parseInt(dayStr);
			} else if (rawStr.matches("^.*[0-9]{1,2}:[0-9]{1,2}.*$") && month != -1 && day != -1) {
				List<NodeList> rawMatchList = this.splitByBr(nodeList.elementAt(i).getChildren().elementAt(0).getChildren());
				if (!ListUtils.isEmpty(rawMatchList)) {
					for (NodeList oneMatchNodes : rawMatchList) {
						RawMatch match = null;
						for (int j = 0; j < oneMatchNodes.size(); j++) {
							Node oneNodeOfMatch = oneMatchNodes.elementAt(j);
							// 抓取比赛文字部分
							if (oneNodeOfMatch instanceof TextNode
									&& match == null) {
								match = this.parseMatchText(
										(TextNode) oneNodeOfMatch, 
										year, month - 1, day);
								if (match == null)
									break;
							}
							// 抓取比赛转播链接
							else if (oneNodeOfMatch instanceof LinkTag
									&& match != null) {
								LinkTag linkTag = (LinkTag) oneNodeOfMatch;
								//linkTag.getAttribute("player_code");
								//linkTag.getAttribute("name");
								//this.parseMatchChannel(linkTag, match);
								match.getChannelNameList().add(linkTag.getAttribute("name"));
							}
						}
						if (match != null)
							matches.add(match);
					}
				}
			}
		}
		return matches;
	}
	
	private List<NodeList> splitByBr(NodeList nodeList) {
		List<NodeList> result = new ArrayList<NodeList>();
		NodeList currentList = new NodeList();
		for (int i = 0; i < nodeList.size(); i++) {
			Node node = nodeList.elementAt(i);
			if (!node.getText().contains("br")) {
				currentList.add(node);
			} else {
				result.add(currentList);
				currentList = new NodeList();
			}
		}
		if (currentList != null && currentList.size() > 0)
			result.add(currentList);
		return result;
	}
	
	private RawMatch parseMatchText(TextNode textNode, int year, int month, int day) {
		String rawMatch = textNode.getText();
		if (rawMatch.matches("^.*[0-9]{1,2}:[0-9]{1,2}.*$")) {
			RawMatch match = new RawMatch();
			// parse time
			int firstSpaceIndex = rawMatch.indexOf(" ");
			if (firstSpaceIndex < 5)
				return null;
			String rawTime = rawMatch.substring(0, firstSpaceIndex);
			if (StringUtils.isEmpty(rawTime))
				return null;
			int colonIndex = rawTime.indexOf(":");
			int hour = Integer.parseInt(rawTime.substring(0, colonIndex));
			int minute = Integer.parseInt(rawTime.substring(colonIndex + 1,
					rawTime.length()));
			Calendar c = new GregorianCalendar();
			c.set(year, month, day, hour, minute, 0);
			match.setStartDate(c.getTime());

			// typeName
			rawMatch = rawMatch.substring(firstSpaceIndex + 1, rawMatch.length()).trim();
			for (Entry<String, Integer> e : SoccerMatch.FOCUSED_TYPE_MAP.entrySet()) {
				if (rawMatch.contains(e.getKey())) {
					match.setTypeName(e.getKey());
					match.setTypeId(e.getValue());
					break;
				}
			}
			
			match.setRawStr(rawMatch);
			return match;
		} else
			return null;
	}
	
	private void parseMatchChannel(LinkTag linkTag, SoccerMatch match) {
		for (Entry<String, Integer> e : SoccerMatch.CHANNEL_MAP.entrySet()) {
			if(linkTag.getText().contains(e.getKey())) {
				match.getChannelIdSet().add(e.getValue());
				break;
			}
		}
	}

	public void filter(List<? extends SoccerMatch> matchList) {
		new ChannelFilterHandler().handle(matchList);
	}
}
